package category

import (
	"context"

	"shop-manager/internal/do"

	"gorm.io/gorm"
)

const (
	MaxPageSize     = 100
	DefaultPageSize = 10
)

//go:generate newc
type CategoryRepo struct {
	db *gorm.DB
}

func (c *CategoryRepo) CreateCategoryMeta(ctx context.Context, data *do.CategoryMeta) (int, error) {
	if err := c.db.WithContext(ctx).Create(&data).Error; err != nil {
		return 0, err
	}
	return data.ID, nil
}

func (c *CategoryRepo) CreateCategoryMetaInBatches(ctx context.Context, data []*do.CategoryMeta) error {
	if err := c.db.WithContext(ctx).CreateInBatches(data, 10).Error; err != nil {
		return err
	}
	return nil
}

func (c *CategoryRepo) UpdateCategoryMeta(ctx context.Context, oneData *do.CategoryMeta) error {
	origin := &do.CategoryMeta{}
	if err := c.db.WithContext(ctx).First(origin, oneData.ID).Error; err != nil {
		return err
	}

	// 只允许修改名称
	origin.Name = oneData.Name
	origin.CategoryType = oneData.CategoryType

	return c.db.WithContext(ctx).Save(&origin).Error
}

func (c *CategoryRepo) DeleteCategoryMeta(ctx context.Context, id int) error {
	return c.db.WithContext(ctx).Delete(&do.CategoryMeta{}, id).Error
}

type ListCategoryMetaParam struct {
	Page     int
	PageSize int

	IDs           []int
	CategoryTypes []do.CategoryType
	Search        string // 模糊搜索

	// 排序, 格式为 field [ASC/DESC], ...
	Sorts string
}

// 分页查询
func (repo *CategoryRepo) ListCategoryMeta(ctx context.Context, param ListCategoryMetaParam) (listData []*do.CategoryMeta, total int64, err error) {
	if param.Page <= 0 {
		param.Page = 1
	}
	if param.PageSize == 0 { // -1 means no limit
		param.PageSize = DefaultPageSize
	}
	if param.PageSize > MaxPageSize {
		param.PageSize = MaxPageSize
	}
	if param.Sorts == "" {
		param.Sorts = "updated_at DESC, category_type ASC, name ASC"
	}

	err = repo.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		if len(param.IDs) > 0 {
			tx = tx.Where("id IN ?", param.IDs)
		}
		if param.Search != "" {
			tx = tx.Where("name LIKE ?", "%"+param.Search+"%")
		}
		if len(param.CategoryTypes) > 0 {
			tx = tx.Where("category_type IN ?", param.CategoryTypes)
		}
		if param.Sorts != "" {
			tx = tx.Order(param.Sorts)
		}

		err = tx.Model(&do.CategoryMeta{}).Find(&listData).Count(&total).Error
		if err != nil {
			return err
		}

		offset := (param.Page - 1) * param.PageSize
		err = tx.Model(&do.CategoryMeta{}).
			Offset(offset).
			Limit(param.PageSize).
			Find(&listData).Error
		if err != nil {
			return err
		}

		return err
	})

	return listData, total, err
}

func (repo *CategoryRepo) GetCategoryMetaMap(ctx context.Context, param ListCategoryMetaParam) (map[int]*do.CategoryMeta, error) {
	listData, _, err := repo.ListCategoryMeta(ctx, param)
	if err != nil {
		return nil, err
	}

	mapData := make(map[int]*do.CategoryMeta)
	for _, item := range listData {
		mapData[item.ID] = item
	}

	return mapData, nil
}
